package com.atwisdom.star.core.dsl.modelClass.hier.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.UuidTool;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierModel;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierPropertiesUtils;
import com.atwisdom.star.core.dao.service.modelClass.hier.HierInstanceService;
import com.atwisdom.star.core.dao.service.modelClass.hier.HierModelService;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.hier.HierModelDslService;
import com.atwisdom.star.core.dsl.modelClass.utils.QueryBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
@AllArgsConstructor
public class HierModelDslServiceImpl implements HierModelDslService {
    private HierModelService hierModelService;
    private HierInstanceService hierInstanceService;
    private HierInstanceDslService hierInstanceDslService;
    private QueryBuilder queryBuilder;

    /**
     * 增加hierProperties数据
     * 1. 删除原来的模型
     * 2. 添加新的模型
     * 3. 更新hier实例
     * @param hierProperties 类名
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<HierModel> add(JSONObject hierProperties) {
        return addHierModel(hierProperties);
    }


    /**
     * 更新
     * @param hierProperties
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject update(JSONObject hierProperties) {
        String model = hierProperties.getString("model");
        String className = hierProperties.getString("className");
        List<HierModel> oldHierModelList = hierModelService.queryByModelAndClassName(model, className);
        hierModelService.removeByModelAndClassName(model, className);
        List<HierModel> newHierModelList = addHierModel(hierProperties);
        // 更新实例
        // if ("staticLogic".equals(model)) {
            hierInstanceDslService.updateByModel(oldHierModelList, newHierModelList);
        // }
        return hierProperties;
    }

    /**
     *
     * @param model 模型表名
     * @param className 新模型类名
     * @param oldClassName 原模型类名
     * @return 返回更新条数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
   public boolean updateClassName(String model, String className, String oldClassName){
        // 1、更新model
        List<HierModel> hierModelList = queryByClassName(model, oldClassName);
        hierModelList.forEach(d-> d.setClassName(className));
        hierModelService.updateBatchById(hierModelList);
        // 2、更新instance
        boolean result = hierInstanceDslService.updateClassName(model, className, oldClassName);
        return result;
    }

    @Override
    public JSONObject query(String model, String className, String condition, String orderBy) {
        condition = queryBuilder.transformOperator(condition);
        QueryWrapper<HierModel> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(model), "model", model);
        queryWrapper.eq(StringUtils.isNotBlank(className), "className", className);
        queryWrapper.apply(StringUtils.isNotBlank(condition), condition);
        queryBuilder.buildOrderBy(queryWrapper, orderBy, "className");
        List<HierModel> hierModelList = hierModelService.list(queryWrapper);
        return fetchHierProperties(hierModelList);
    }

    /**
     * 复制一份model, 并更改名称
     * @param model
     * @param className
     * @param oldClassName
     * @return  新的HierModel集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<HierModel> clone(String model, String className, String oldClassName) {
        List<HierModel> hierModelList = queryByClassName(model, oldClassName);
        hierModelList.forEach(d->{
            d.setClassName(className);
            d.setId(null);
        });
        hierModelService.saveBatch(hierModelList);
        return hierModelList;
    }

    /**
     * 按类名查询
     *
     * @param className 模型名称
     * @return
     */
    @Override
    public List<HierModel> queryByClassName(String model, String className) {
        List<HierModel> hierModelList = hierModelService.queryByModelAndClassName(model, className);
        return hierModelList;
    }

    /**
     * 删除模型及实例
     *
     * @param className 模型id 删除模型
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByClassName(String model, String className) {
        hierModelService.removeByModelAndClassName(model, className);
        hierInstanceService.removeByModelAndClassName(model, className);
        return true;
    }

    /**
     * 按classNames 删除模型及实例
     *
     * @param classNameList 模型id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByClassNames(String model, List<String> classNameList) {
        hierModelService.removeByModelAndClassNameList(model, classNameList);
        hierInstanceService.removeByModelAndClassNameList(model, classNameList);
        return true;
    }

    @Override
    public HierModel queryByNodeId(String model, String className, String nodeId) {
        LambdaQueryWrapper<HierModel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HierModel::getModel, model)
                .eq(HierModel::getClassName, className)
                .eq(HierModel::getNodeId, nodeId);
        return hierModelService.getOne(wrapper);
    }

    @Override
    public HierModel queryByName(String model, String className, String name) {
        return null;
    }

    /**
     * 根据propertyName，获取节点的defaultValue
     * @param model
     * @param className
     * @param nodeId
     * @param propertyName
     * @param <T>
     * @return
     */
    public <T> T fetchPropDefaultValueByNodeId(String model, String className, String nodeId, String propertyName) {
        HierModel hierModel = queryByNodeId(model, className, nodeId);
        return fetchPropDefaultValueByPropName(hierModel, propertyName);
    }

    /**
     *  根据 propertyName，获取节点的defaultValue
     * @param hierModel
     * @param propertyName
     * @param <T>
     * @return
     */
    public <T> T fetchPropDefaultValueByPropName(HierModel hierModel, String propertyName) {
        JSONArray properties = hierModel.getProperties();
        for (int i = 0; i < properties.size(); i++) {
            JSONObject property = properties.getJSONObject(i);
            String name = property.getString("name");
            if (propertyName.equals(name)) {
                return (T)property.get("defautValue");
            }
        }
        return null;
    }


    /**
     *
     * @param model
     * @param className
     * @param nodeName nodeName必须唯一
     * @param propertyName
     * @param <T>
     * @return
     */
    @Override
    public <T> T fetchByPropertyName(String model, String className, String nodeName, String propertyName) {
        List<HierModel> nodeList = queryByClassName(model, className);
        HierModel hierModel = nodeList.stream().filter(d -> d.getName().equals(nodeName)).findFirst().get();
        return fetchPropDefaultValueByPropName(hierModel, propertyName);
    }

    @Override
    public <T> T fetchCondition(String model, String className) {
        return fetchByPropertyName(model, className, "config", "condition");
    }

    @Override
    public <T> T fetchInsFlag(String model, String className) {
        return fetchByPropertyName(model, className, "config", "createRouting");
    }

    /**
     * 按名称查找指定的节点
     */



    /**
     * 增加hierModel
     * @param hierProperties
     * @return
     */
    private List<HierModel> addHierModel(JSONObject hierProperties) {
        List<HierModel> hierModelList = buildModelList(hierProperties);
        hierModelService.saveBatch(hierModelList);
        return hierModelList;
    }

    /**
     * 构建hierModelList
     * @param hierProperties
     * @return
     */
    private List<HierModel> buildModelList(JSONObject hierProperties) {
        List<HierModel> hierModelList =  new ArrayList<>();
        String type = hierProperties.getString("type");
        if ("list".equals(type)) {
            HierModel hierModel = buildModel(hierProperties);
            hierModelList.add(hierModel);
        } else {
            hierModelList.addAll(buildHierModelListByContent(hierProperties));
        }
        return hierModelList;
    }

    /**
     * 构建hierModelList
     * @param hierProperties，必须包含content数组
     * @return
     */
    private List<HierModel> buildHierModelListByContent(JSONObject hierProperties) {
        List<HierModel> hierModelList = new ArrayList<>();
        JSONArray contentArray = hierProperties.getJSONArray("content");
        for (int i = 0; i < contentArray.size(); i++) {
            HierModel hierModel = buildModel(contentArray.getJSONObject(i));
            hierModel.setModel(hierProperties.getString("model"));
            hierModel.setClassName(hierProperties.getString("className"));
            hierModel.setType(hierProperties.getString("type"));

            hierModelList.add(hierModel);
        }
        return hierModelList;
    }

    /**
     * 构建hierModelList
     * @param hierProperties
     * @return
     */
    public static HierModel buildModel(JSONObject hierProperties) {
        // 组建新对象
        HierModel hierModel = new HierModel();
        hierProperties.put("id", null);
        BeanUtil.copyProperties(hierProperties, hierModel);
        JSONObject link = hierProperties.getJSONObject("link");
        if (link != null) {
            String linkModel = link.getString("linkModel");
            String linkClassName = link.getString("linkClassName");
            String linkType = link.getString("linkType");
            hierModel.setLinkModel(linkModel);
            hierModel.setLinkClassName(linkClassName);
            hierModel.setLinkType(linkType);
        }

        hierModel.setNodeId(hierProperties.containsKey("nodeId") ? hierProperties.getString("nodeId") : UuidTool.getUUID32());
        return hierModel;
    }


    private JSONObject fetchHierProperties(List<HierModel> modelList) {
        HierPropertiesUtils hierProps = new HierPropertiesUtils(modelList);
        return hierProps.fetchHierProperties();
    }
}
